var SM4Init = ($, algorithm, defaultTxt) => {
    const _algorithm = algorithm.toLowerCase();
    /*
    Store the calculated ciphertext and IV here, so we can decrypt the message later.
    */
    let ciphertext, lastEncryptMsg;
    let iv;
    let key;

    /*
    Fetch the contents of the "message" textbox, and encode it
    in a form we can use for the encrypt operation.
    */
    async function getMessageEncoding() {
        const messageBox = $(".crypt-message");
        lastEncryptMsg = messageBox.value.trim();
        if(!lastEncryptMsg) {
          messageBox.value = lastEncryptMsg = defaultTxt || '一去二三里';
        }
        await initIvAndKey();

        return encode(lastEncryptMsg);
    }
    async function initIvAndKey(){
        iv = getLengthEncodeStr($('.iv'));
        key = await getImportKey($(".key"), algorithm, showErr); 
    }

    function getParams() {
        return algorithm.includes('CTR') ?  { name: algorithm, counter: iv, length: 64 } : { name: algorithm, iv };
    }
    // 加密、解密
    async function encryptFn(encoded){
        return await window.crypto.subtle.encrypt(getParams(), key, encoded );
    }
    async function decryptFn(ciphertext){
        return await window.crypto.subtle.decrypt(getParams(), key, ciphertext);
    }
    const initHtml = () => {
        var node = document.querySelector(".sm4-html").cloneNode(true);
        node.classList.remove('sm4-html');
        node.classList.add(_algorithm);
        document.querySelector('.sm4-html').parentElement.appendChild(node);
        $('.examples-tips').textContent = algorithm + ' ' + $('.examples-tips').textContent;
    }
    initHtml();

    const decryptedValue = $(".decrypted-value");
    const ciphertextBase64 = $(".ciphertext-base64"), ciphertextHex = $(".ciphertext-hex"), ciphertextBinary = $(".ciphertext-binary");
    const fadeShow = (dom) => {
        dom.classList.add('fade-in');
        dom.addEventListener('animationend', () => {
            dom.classList.remove('fade-in');
        });
    }
    /*
    Get the encoded message, encrypt it and display a representation
    of the ciphertext in the "Ciphertext" element.
    */
    async function encryptMessage() {
        let encoded = await getMessageEncoding();
        ciphertext = await encryptFn(encoded);

        $('.ciphertext').style.display = 'block';
        // fadeShow(ciphertextValue);
        // base64密文
        ciphertextBase64.value = btoa(String.fromCharCode.apply(null,new Uint8Array(ciphertext)));
        ciphertextHex.value = arrayBufferToHex(ciphertext);
        ciphertextBinary.value = new Uint8Array(ciphertext);
    }
    
    function stringToArrayBuffer(str){
        if(/^[\d ,]+$/.test(str) && (str.includes(',') || str.includes(' '))){ //纯数字用逗号和空格分隔的，统一转为hex
            var prefix = '';
            if(/^[01 ,]+$/.test(str)){ //二进制
                prefix = '0b';
            }
            const tmp = str.includes(',')?str.split(','):str.split(' ');
            let padLen = 2;
            if(tmp && tmp.length > 0 && tmp[0].length == 4){
                padLen = 1;
            }
            str = hexToArrayBuffer(tmp.map((n)=>Number(prefix + n).toString(16).padStart(padLen,'0')).join(''));
        }else if(/^[A-Fa-f0-9]+$/.test(str)) { // 若为hex，将其转为ArrayBuffer
            str = hexToArrayBuffer(str);
        }else if(/^[A-Za-z0-9+/=]+$/.test(str)) { // 若为base64，将其转为ArrayBuffer
            str = base64ToArrayBuffer(str);
        }
        return str;
    }
    const showErr = (str)=>$('.error-tip').textContent = str;
    /*
    Fetch the ciphertext and decrypt it.
    Write the decrypted message into the "Decrypted" box.
    */
    async function decryptMessage(alreadyTry) {
        const msg = $(".crypt-message").value.trim();
        if(!msg || !$('.iv').value || !$(".key").value) {
            showErr('请输入解密文本、解密KEY和IV');
            return;
        }

        await initIvAndKey(); // 初始化key和iv

        let decrypted = '';
        try {
            decrypted = await decryptFn(stringToArrayBuffer(msg))
        } catch (e) {
            console.log(e);
            showErr('解密算法、解密文本、KEY、IV不正确')
            return;
        }

        $('.decrypted').style.display = 'block';
        fadeShow(decryptedValue);
        decryptedValue.value = decode(decrypted);
    }

    // 清除错误提示和结果
    const clearInfo = (type) => {
        $('.error-tip').textContent = '';
        if(type == 1){
            ciphertextBase64.value = ciphertextHex.value = ciphertextBinary.value = '';
        }else{
            decryptedValue.value = '';
        }
    };
    // 加解密事件
    $(".encrypt-button").addEventListener("click", async () => {
        clearInfo(1);
        encryptMessage();
    });
    $(".decrypt-button").addEventListener("click", async () => {
        clearInfo(2);
        decryptMessage();
    });

    // 用于一键性能测试
    allPerformance.push({
        name: `${algorithm}加密`, fn: getTestFn(encryptFn), resultId: `#tr-${_algorithm}-encrypt`
    }, {
        name: `${algorithm}解密`, fn: getTestFn(decryptFn), encryptFn, resultId: `#tr-${_algorithm}-decrypt`
    })
};